package net.oschina.arvin.sqlbuilder.utils;

import net.oschina.arvin.sqlbuilder.exceptions.SqlBuilderException;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

/**
 * @author Arvin
 * @time 2017/11/15 23:43
 */
public class Util {

    public static boolean isBlank(String value) {
        return null == value || "".equals(value);
    }

    public static boolean isNotBlank(String value) {
        return null != value && !"".equals(value.trim());
    }

    public static final String DEFAULT_DB_WRAP_OPEN = "`";
    public static final String DEFAULT_DB_WRAP_CLOSE = "`";
    /** 下划线 */
    public static final String UNDERLINE = "_";

    /**
     * 使用 open, close 包装列名称
     *
     * @param columnName 数据库列名称
     * @return 返回包裹后的名称
     */
    public static String wrapColumnName(String columnName) {
        return wrapDbAttrName(columnName);
    }

    public static String unWrapColumnName(String columnName) {
        return unWrapDbAttrName(columnName);
    }

    /**
     * 使用 open, close 包装数据库表名称
     *
     * @param tableName 数据库表名称
     * @return 返回包裹后的名称
     */
    public static String wrapTableName(String tableName) {
        return wrapDbAttrName(tableName);
    }

    public static String unWrapTableName(String tableName) {
        return unWrapDbAttrName(tableName);
    }

    /**
     * 包装数据库列或属性名称
     *
     * @param dbAttrName 数据库属性名称
     */
    public static String wrapDbAttrName(String dbAttrName) {
        AssertUtil.assertNotBlank(dbAttrName, "要包装的数据库字段不能为空！");
        String realOpen = DEFAULT_DB_WRAP_OPEN;
        String realClose = DEFAULT_DB_WRAP_CLOSE;

        dbAttrName = unWrapDbAttrName(dbAttrName);

        dbAttrName = realOpen + dbAttrName + realClose;

        return dbAttrName;
    }

    /**
     * 解包装数据库字段
     *
     * @param dbAttrName 数据库属性名称
     */
    public static String unWrapDbAttrName(String dbAttrName) {
        String realOpen = DEFAULT_DB_WRAP_OPEN;
        String realClose = DEFAULT_DB_WRAP_CLOSE;

        while (dbAttrName.startsWith(realOpen)) {
            dbAttrName = dbAttrName.substring(realOpen.length());
        }

        while (dbAttrName.endsWith(realClose)) {
            dbAttrName = dbAttrName.substring(0, dbAttrName.length() - realClose.length());
        }

        return dbAttrName;
    }

    /**
     * 给表达式前后加上括号对
     *
     * @param express 表达式
     */
    public static String wrapBracketPair(String express) {
        return express.matches("^ *\\(.*\\) *$") ? express.trim() : "(" + express.trim().replaceFirst("^ *\\(", "").replaceFirst("\\) *$", "") + ")";
    }

    /**
     * 将下划线转换成驼峰， 并且首字母小写
     *
     * @param value                要转换的字符串
     * @param firstLetterLowerCase 首字母是否小写
     * @return
     */
    public static String underlineToHump(String value, boolean firstLetterLowerCase) {
        if (isNotBlank(value)) {
            String resultValue = value;
            if (resultValue.contains(UNDERLINE)) {
                String[] array = value.split(UNDERLINE);
                StringBuilder builder = new StringBuilder();
                for (int i = 0; i < array.length; ++i) {
                    String sub = array[i];
                    if (i > 0) {
                        sub = String.valueOf(sub.charAt(0)).toUpperCase() + sub.substring(1);
                    }
                    builder.append(sub);
                }
                resultValue = builder.toString();
            }
            if (firstLetterLowerCase) {
                return firstLetterToLowerCase(resultValue);
            }
        }
        return value;
    }

    /**
     * 首字母小写
     *
     * @param value 要处理的字符串
     * @return
     */
    public static String firstLetterToLowerCase(String value) {
        AssertUtil.assertNotBlank(value, "要首字母小写的字符串不能为空！");
        if (value.length() == 1) {
            return value.toLowerCase();
        }
        return String.valueOf(value.charAt(0)).toLowerCase() + value.substring(1);
    }

    /**
     * 首字母大写
     *
     * @param value 要处理的字符串
     * @return
     */
    public static String firstLetterToUpperCase(String value) {
        AssertUtil.assertNotBlank(value, "要首字母大写的字符串不能为空！");
        if (value.length() == 1) {
            return value.toUpperCase();
        }
        return String.valueOf(value.charAt(0)).toUpperCase() + value.substring(1);
    }

    /**
     * 驼峰转 下划线分割
     *
     * @param value 要转换的字符串
     * @return
     */
    public static String humpToUnderline(String value) {
        return firstLetterToLowerCase(value).replaceAll("([A-Z]+)", "_$1").toLowerCase();
    }

    /**
     * 生成UUID并去掉横杠，转化为大写
     *
     * @return
     */
    public static String generateUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
    }


    public static boolean isOverZero(String numberString) {
        if (null == numberString) {
            return false;
        }

        try {
            return Long.valueOf(String.valueOf(numberString)) > 0;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    public static boolean isValidPrimaryKeyValue(Object value) {
        if (null == value) {
            return false;
        }
        if (value instanceof CharSequence) {
            return Util.isNotBlank(String.valueOf(value));
        }
        return isOverZero(String.valueOf(value));
    }

    /**
     * 创建当前时间，根据指定的时间类型
     *
     * @param timeType 时间类型
     * @return
     */
    public static Object createCurrentTimeByTimeType(Class<?> timeType) {
        AssertUtil.assertTrue(isTimeType(timeType), "不支持的时间类型，无法生成！");
        long current = System.currentTimeMillis();
        if (timeType == java.util.Date.class) {
            return new java.util.Date();
        }
        if (timeType == java.sql.Date.class) {
            return new java.sql.Date(current);
        }
        if (timeType == java.sql.Timestamp.class) {
            return new java.sql.Timestamp(current);
        }
        if (timeType == java.sql.Time.class) {
            return new java.sql.Time(current);
        }

        throw new SqlBuilderException("未知的时间类型，无法生成！");
    }

    @SuppressWarnings({"unchecked"})
    public static boolean isTimeType(Class<?> timeType) {
        if (null == timeType) {
            return false;
        }
        Set<Class<?>> supportTypes = new HashSet<Class<?>>(Arrays.asList(
                java.util.Date.class,
                java.sql.Date.class,
                java.sql.Timestamp.class,
                java.sql.Time.class
        ));
        return supportTypes.contains(timeType);
    }

    @SuppressWarnings({"unchecked"})
    public static boolean isStringType(Class<?> type) {
        if (null == type) {
            return false;
        }
        Set<Class<?>> supportTypes = new HashSet<Class<?>>(Arrays.asList(
                String.class, CharSequence.class
        ));
        return supportTypes.contains(type);
    }

    @SuppressWarnings({"unchecked"})
    public static boolean isIntType(Class<?> type) {
        if (null == type) {
            return false;
        }
        Set<Class<?>> supportTypes = new HashSet<Class<?>>(Arrays.asList(
                int.class, Integer.class
        ));
        return supportTypes.contains(type);
    }

    @SuppressWarnings({"unchecked"})
    public static boolean isLongType(Class<?> type) {
        if (null == type) {
            return false;
        }
        Set<Class<?>> supportTypes = new HashSet<Class<?>>(Arrays.asList(
                long.class, Long.class
        ));
        return supportTypes.contains(type);
    }

    @SuppressWarnings({"unchecked"})
    public static boolean isBooleanType(Class<?> type) {
        if (null == type) {
            return false;
        }
        Set<Class<?>> supportTypes = new HashSet<Class<?>>(Arrays.asList(
                boolean.class, Boolean.class
        ));
        return supportTypes.contains(type);
    }


    /**
     * 是否是原始类型
     *
     * @param type 类类型
     * @return
     */
    @SuppressWarnings({"unchecked"})
    public static boolean isPrimitiveType(Class<?> type) {
        if (null == type) {
            return false;
        }
        Set<Class<?>> primitiveTypes = new HashSet<Class<?>>(Arrays.asList(
                int.class, long.class, char.class, short.class,
                byte.class, boolean.class, float.class, double.class
        ));

        return primitiveTypes.contains(type);
    }

    /**
     * 是否是数字类型
     *
     * @param type
     * @return
     */
    @SuppressWarnings({"unchecked"})
    public static boolean isNumberType(Class<?> type) {
        if (null == type) {
            return false;
        }
        Set<Class<?>> numberTypes = new HashSet<Class<?>>(Arrays.asList(
                int.class, long.class, short.class,
                float.class, double.class,
                Integer.class, Long.class, Number.class, Double.class,
                Float.class, Short.class, Byte.class, BigDecimal.class,
                BigInteger.class
        ));

        return numberTypes.contains(type);
    }

    public static Number toNumber(Object value) {
        if (null == value) {
            return null;
        }
        if (isNumberType(value.getClass()) && value instanceof Number) {
            return (Number) value;
        }
        return null;
    }

    /**
     * 获取指定的classType的默认值
     *
     * @param classType 类
     * @return 原始类型按照原始类型默认值，包装类型则为null
     */
    public static Object getTypeDefaultValue(Class<?> classType) {
        AssertUtil.assertNotNull(classType, "要计算的类类型不能为null");

        if (classType == int.class) return 0;
        if (classType == long.class) return 0L;
        if (classType == char.class) return 0;
        if (classType == boolean.class) return false;
        if (classType == float.class) return (float) 0;
        if (classType == double.class) return (double) 0;
        if (classType == byte.class) return (byte) 0;
        if (classType == short.class) return (short) 0;

        return null;
    }

    /**
     * 转成 java.util.Date 对象
     *
     * @param value 时间值
     * @return
     */
    public static java.util.Date convertToJavaUtilDate(Object value) {
        if (null == value) {
            return null;
        }

        if (value instanceof java.util.Date) {
            return (java.util.Date) value;
        }

        return null;
    }

    /**
     * 符合条件的查询类
     */
    private static String[] ACCEPT_QUERY_CONDITION_SUFFIXES = new String[]{
            "Query", "Dto", "DTO", "Vo", "VO", "Condition", "Bean"
    };

    public static boolean isValidQueryCondition(Object queryCondition) {
        if (null == queryCondition) {
            return true;
        }
        return isValidQueryConditionType(queryCondition.getClass());
    }

    public static boolean isValidQueryConditionType(Class<?> queryConditionType) {
        if (null == queryConditionType) {
            return false;
        }
        String className = queryConditionType.getSimpleName();
        for (String validSuffix : ACCEPT_QUERY_CONDITION_SUFFIXES) {
            if (className.endsWith(validSuffix)) {
                return true;
            }
        }
        return false;
    }

    public static void checkQueryCondition(Object queryCondition) {
        AssertUtil.assertTrue(isValidQueryCondition(queryCondition),
                "不符合规定的查询条件，查询条件对象类名必须是以下后缀结尾：" + validQueryConditionSuffixesToString());
    }

    public static void checkQueryConditionType(Class<?> queryConditionType) {
        AssertUtil.assertTrue(isValidQueryConditionType(queryConditionType),
                "不符合规定的查询条件类型，查询条件类名必须是以下后缀结尾：" + validQueryConditionSuffixesToString());
    }

    public static String validQueryConditionSuffixesToString() {
        StringBuilder builder = new StringBuilder("[");
        for (String validSuffix : ACCEPT_QUERY_CONDITION_SUFFIXES) {
            builder.append(validSuffix).append(", ");
        }
        builder.setLength(builder.length() - 2);
        builder.append("]");
        return builder.toString();
    }

    public static boolean isNotEmpty(Collection<?> collection) {
        return null != collection && !collection.isEmpty();
    }

    public static boolean isEmpty(Collection<?> collection) {
        return null == collection || collection.isEmpty();
    }

    public static boolean isValidPagingParams(int pageNo, int pageSize) {
        return pageNo > 0 && pageSize > 0;
    }

    public static boolean isMapInstance(Object object) {
        return null != object && (object instanceof Map);
    }
}
